
package com.kq.xtoolkit;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.view.Gravity;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.animation.AccelerateInterpolator;
import android.widget.Toast;

import com.kq.xtoolkit.utils.XUtils;
import com.kq.xtoolkit.view.BallView;
import com.kq.xtoolkit.view.BallView.State;

/*
 * create this service to handle view's entire life
 */
public class XToolKitService extends Service {
    private WindowManager wm = null;

    private Context mContext;
    //view
    private BallView ballView;
    //variable
    private int mStatusbarHeight;
    // handler constant
    private static final int MSG_START_BOUNCER_ANIMATION = 1;
    public static final int MSG_UPDATE_BALL_POSITION = 2;
    private static final int MSG_START_HIDE_ANIMATION=3;
    public static final int MSG_FLING = 4;
    public static final int MSG_SET_BALL_VISIBLE = 5;
    public static final int MSG_LIGHT_FLASH = 6;
    public static final int MSG_LOCK_SCREEN = 7;
    public static final int MSG_SET_BALL_HALF_TRANSPARENT = 8;
    public static final int MSG_START_SETTING_ACTIVITY = 9;

    // flash light
    private Camera mCamera;
    private boolean hasFlashLight;
    private boolean isFlashOn = false; //true:on false:off

    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case MSG_START_BOUNCER_ANIMATION:
                        //startBouncerAnimation();
                    break;
                case MSG_UPDATE_BALL_POSITION:
                    Bundle bundle = msg.getData();
                    if (bundle != null) {
                        float x = bundle.getFloat("x");
                        float y = bundle.getFloat("y");
                        updateBallViewPosition(x, y);
                    }
                    break;
                case MSG_START_HIDE_ANIMATION:
                    if (ballView.getState() == State.IDLE) {
                        startHideAnimation();
                    }
                    break;
                case MSG_FLING:
                    Bundle data = msg.getData();
                    if (data != null) {
                        float vx = data.getFloat("velocityX");
                        float vy = data.getFloat("velocityY");
                        startFlingAnimation(vx, vy);
                    }
                    break;
                case MSG_SET_BALL_VISIBLE:
                    int visible = msg.arg1;
                    ballView.setVisibility(visible);
                    break;
                case MSG_LIGHT_FLASH:
                    flashLight();
                    break;
                case MSG_SET_BALL_HALF_TRANSPARENT:
                    if (ballView != null) {
                        //ballView.setAlphaValue(BallView.HALF_TRANSPARANT);
                    }
                    break;
                case MSG_START_SETTING_ACTIVITY:
                    Intent intent = new Intent(mContext, XToolKitSettings.class);
                    intent.setAction(Intent.ACTION_MAIN);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    getApplicationContext().startActivity(intent);
                    break;
            }
        }

    };


    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
        // init global variable
        mStatusbarHeight = XUtils.getStatusBarHeight(mContext);
        wm = (WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        // init ball view
        ballView = new BallView(mContext);
        ballView.setServiceHandler(mHandler);
        // must attach panel to window before ball
        attachBallViewToWindow();
        // if hardware support flashlight
        isFlashOn = false;
        hasFlashLight = XUtils.isHardwareSupportFlashLight(mContext);
    }

    private synchronized void flashLight() {
        if (!hasFlashLight) {
            Toast.makeText(mContext, R.string.camera_not_support_prompt, Toast.LENGTH_SHORT).show();
            return;
        }
        if (!isFlashOn) {
            mCamera = XUtils.getCameraInstance();
            Camera.Parameters param = mCamera.getParameters();
            param.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
            mCamera.setParameters(param);
            mCamera.startPreview();
            isFlashOn = true;
            setBallImage();
        } else {
            // turn off
            Camera.Parameters param = mCamera.getParameters();
            mCamera.stopPreview();
            param.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
            mCamera.setParameters(param);
            mCamera.startPreview();
            mCamera.release();
            isFlashOn = false;
            setBallImage();
        }
    }

    private void startFlingAnimation(float vx, float vy) {
        float ratio = vy / vx;
        int ballX = getBallXPosition();
        int ballY = getBallYPosition();
        int endX = XUtils.getWindowsWidth(mContext) - getBallWidth()/2;
        float endY = ballY + (endX - ballX) * ratio;
        // x animation
        ValueAnimator animationX = ValueAnimator
                .ofFloat(ballX, endX);
        animationX.setInterpolator(new AccelerateInterpolator());
        animationX.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                String value = ((ValueAnimator)animation).getAnimatedValue().toString();
                updateBallViewPosition(Float.parseFloat(value), 0);
            }
        });
        animationX.addListener(new AnimatorListener() {
            
            @Override
            public void onAnimationStart(Animator animation) {
                // TODO Auto-generated method stub
                
            }
            
            @Override
            public void onAnimationRepeat(Animator animation) {
                // TODO Auto-generated method stub
                
            }
            
            @Override
            public void onAnimationEnd(Animator animation) {
                XUtils.vibrate(mContext, 20);
                mHandler.sendEmptyMessageDelayed(MSG_START_HIDE_ANIMATION, 3000);
            }
            
            @Override
            public void onAnimationCancel(Animator animation) {
                // TODO Auto-generated method stub
                
            }
        });
        animationX.setDuration(200);
        // y animation
        ValueAnimator animationY = ValueAnimator
                .ofFloat(ballY, endY);
        animationY.setInterpolator(new AccelerateInterpolator());
        animationY.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                String value = ((ValueAnimator)animation).getAnimatedValue().toString();
                updateBallViewPosition(0, Float.parseFloat(value));
            }
        });
        animationY.setDuration(200);
        // animation set
        AnimatorSet animSetXY = new AnimatorSet();
        animSetXY.playTogether(animationX, animationY);
        animSetXY.start();
    }

    @Override
    public void onDestroy() {
        if (ballView != null) {
            wm.removeView(ballView);
        }
        if (mCamera != null) {
            if (isFlashOn)
                flashLight();
            mCamera.release();
        }
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // init global flag from preference
        initPrefFlag();
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    // get values from preference file and init global variable
    private void initPrefFlag() {
        SharedPreferences settings = getSharedPreferences(XToolKitSettings.PREFS_NAME, 0);
    }

    private void attachBallViewToWindow() {
        WindowManager.LayoutParams wmParams = ((XToolKitApplication)getApplication())
                .getBallParams();
        wmParams.type = LayoutParams.TYPE_PHONE;
        wmParams.format = PixelFormat.RGBA_8888;
        wmParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE
                | LayoutParams.FLAG_LAYOUT_NO_LIMITS;
        wmParams.gravity = Gravity.LEFT | Gravity.TOP;
        wmParams.x = 0;
        wmParams.y = 0;
        wmParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
        wmParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
        wm.addView(ballView, wmParams);
    }


    private void updateBallViewPosition(float x, float y) {
        WindowManager.LayoutParams wmParams = ((XToolKitApplication)getApplication())
                .getBallParams();
        float leftOffset = ballView.getWidth()/2;
        float rightOffset = XUtils.getWindowsWidth(mContext) - leftOffset;
        float upOffset = ballView.getHeight()/2;
        float downOffset = XUtils.getWindowsHeight(mContext) - upOffset;
        if (x >= leftOffset) {
            if (x >= rightOffset) {
                if (isFlashOn) {
                    ballView.setImageResource(R.drawable.ball_attached_pressed);
                } else {
                    ballView.setImageResource(R.drawable.ball_attached);
                }
            } else {
                if (isFlashOn) {
                    ballView.setImageResource(R.drawable.ball_normal_pressed);
                } else {
                    ballView.setImageResource(R.drawable.ball_normal);
                }
            }
            wmParams.x = (int)Math.ceil(x - leftOffset);
        }
        if (y >= upOffset && y <= downOffset) {
            wmParams.y = (int)Math.ceil(y - upOffset - mStatusbarHeight);
        }
        wm.updateViewLayout(ballView, wmParams);
    }

    private void setBallImage() {
        float rightOffset = XUtils.getWindowsWidth(mContext) - ballView.getWidth() / 2;
        int x = getBallXPosition();
        if (x >= rightOffset) {
            if (isFlashOn) {
                ballView.setImageResource(R.drawable.ball_attached_pressed);
            } else {
                ballView.setImageResource(R.drawable.ball_attached);
            }
        } else {
            if (isFlashOn) {
                ballView.setImageResource(R.drawable.ball_normal_pressed);
            } else {
                ballView.setImageResource(R.drawable.ball_normal);
            }
        }
    }
    private void startHideAnimation() {
        int ballX = getBallXPosition();
        int endX = ballX + (int)(getBallWidth() * 0.7f);
        ValueAnimator animationX = ValueAnimator
                .ofFloat(ballX, endX);
        animationX.setInterpolator(new AccelerateInterpolator());
        animationX.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                String value = ((ValueAnimator)animation).getAnimatedValue().toString();
                updateBallViewPosition(Float.parseFloat(value), 0);
            }
        });
        animationX.setDuration(200);
        animationX.start();
    }

    private int getBallXPosition() {
        WindowManager.LayoutParams wmParams = ((XToolKitApplication)getApplication())
        .getBallParams();
        return wmParams.x + getBallWidth()/2;
    }

    private int getBallYPosition() {
        WindowManager.LayoutParams wmParams = ((XToolKitApplication)getApplication())
        .getBallParams();
        return wmParams.y + getBallHeight()/2;
    }

    private int getBallWidth() {
        int width = 0;
        if (ballView != null) {
            width = ballView.getWidth();
        }
        return width;
    }

    private int getBallHeight() {
        int height = 0;
        if (ballView != null) {
            height = ballView.getHeight();
        }
        return height;
    }
}
